package com.cd.questionBank.util;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * @Description 单例类
 * 刷新分为首次刷新和后续刷新 首次使用length来判断 后续通过同步任务来搞
 * @Author lqq
 * @Date 2024/11/6 9:43
 **/

public class DomainCache implements Serializable {

    private static final long serialVersionUID = 1L;

    private static volatile DomainCache instance;
    //只获取domain的id和code 考虑到domain对象过大 不采用后面为对象的存储方式
    private Map<String, String> domainIdToCodeMap = new HashMap<>();
    private Map<String, String> domainIdToEnumMap = new HashMap<>();

    private final Object lock = new Object();

    //判断是否已经在同步中
    private boolean isSyncing = false;
    //private static boolean isAvailable = false;//是否可用、综合考虑同步和写入成功

//    static {
//        //init
//        domainIdToCodeMap = new HashMap<>();
//        domainIdToEnumMap = new HashMap<>();
//    }

    // 获取单例实例的方法
    public static DomainCache getInstance() {
        if (instance == null) {
            synchronized (DomainCache.class) {
                if (instance == null) {
                    instance = new DomainCache();
                }
            }
        }
        return instance;
    }

    //私有化构造方法
    private DomainCache() {

    }

    //    public static synchronized String getDomainCode(String domainId) {
//        return domainIdToCodeMap.get(domainId);
//    }
//
//    public static synchronized String getDomainEnum(String domainId) {
//        return domainIdToEnumMap.get(domainId);
//    }
    public Map<String, String> getAll() {
        synchronized (lock) {
            while (isSyncing) {
                try {
                    System.out.println("数据未准备好，等待...");
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("数据已准备好，开始输出...");
        }
        return domainIdToCodeMap;
    }

    //刷新
    public String refresh(List<LocalDomainDto> domains) {
        //调用同步有两种 一种是任务同步 一种是手动同步 不存在代码里同步的情况 所以在同步直接拒绝即可
        if (isSyncing) {
            return "正在同步中，无法重复调用";
        }
        isSyncing = true;
        //睡眠十秒 留给我操作空间
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //isAvailable = false; 考虑到同步任务进行时 或其他未知异常 需有兜底方案
        try {
            domainIdToCodeMap.clear();
            domainIdToEnumMap.clear();
            for (LocalDomainDto domainDto : domains) {
                domainIdToCodeMap.put(domainDto.getId(), domainDto.getDomainCode());
                domainIdToEnumMap.put(domainDto.getId(), domainDto.getReferenceCode());
            }
            //isAvailable = true;
        } catch (Exception e) {
            e.printStackTrace();
            //isAvailable = false;
            return "同步失败: " + e.getMessage();
        } finally {
            isSyncing = false;
            synchronized (lock) {
                lock.notifyAll();
            }
        }

        return "同步完成";
    }

    public boolean isAvailable() {
        synchronized (lock) {
            while (isSyncing) {
                try {
                    System.out.println("数据在同步无法判断，请等待...");
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("数据已准备完成，开始判断是否可使用");
        }
        return domainIdToCodeMap.size() > 0
                && domainIdToEnumMap.size() > 0;
    }
}
